package com.zhangyue.wqercs.waveview;

import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Region;
import android.graphics.Xfermode;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.animation.LinearInterpolator;

public class WaveView extends View {
    private int waveLength;//波长
    private int waveHeight;//波峰
    private int waveImage;//圆形图片资源id
    private boolean raise;//是否涨潮效果
    private int originY;//水平线的Y坐标
    private int during;//一个波浪的运行的持续时间
    private Bitmap bitmap;//需要绘制的圆形图片
    private Paint paint;//画笔变量
    private int height;//控件的高度
    private int width;//控件的宽度
    private Path path;//绘制波浪的path路经
    private int dx;//动画的移动增量
    private int dy;//制作涨潮效果增量
    private Region region;//找到中心点的区域变量

    public WaveView(Context context,  AttributeSet attrs) {
        super(context, attrs);
        init(context,attrs);
    }

    private void init(Context context, AttributeSet attrs) {
        //获取配置文件中的常用属性
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.WaveView);
        waveHeight = (int)a.getDimension(R.styleable.WaveView_waveHeight,200);
        waveLength = (int)a.getDimension(R.styleable.WaveView_waveLength,600);
        waveImage = a.getResourceId(R.styleable.WaveView_waveImage,0);
        raise = a.getBoolean(R.styleable.WaveView_raise,true);
        originY = (int)a.getDimension(R.styleable.WaveView_originY,0);
        during = a.getInt(R.styleable.WaveView_during,1000);
        a.recycle();

        //通过图片资源id加载图片bitmap对象
        BitmapFactory.Options options =new BitmapFactory.Options();
        options.inSampleSize = 1;
        if(waveImage > 0){ 
            bitmap = BitmapFactory.decodeResource(getResources(),waveImage,options);
        }else {
            bitmap = BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher,options);
        }
        //调用自定义方法，将图片创建为圆形图片
        bitmap = getCircleBitmap(bitmap);

        //绘制画笔工具
        paint = new Paint();
        //将画笔设置波浪颜色
        paint.setColor(getResources().getColor(R.color.waveColor));
        //注：如果path是一个封闭区域，那么画笔将会填充该区域，从而形成波浪效果
        paint.setStyle(Paint.Style.FILL_AND_STROKE);
        //创建path对象。这个path就是用来绘制波浪效果对象
        path =new Path();
    }

    private Bitmap getCircleBitmap(Bitmap bitmap) {
        if (bitmap == null){
            return null;
        }
        //重新创建一个图片大小的画板
        Bitmap circleBitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(),
                Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(circleBitmap);
        Paint paint = new Paint();
        Rect rect = new Rect(0,0,bitmap.getWidth(),bitmap.getHeight());
        RectF rectF = new RectF(0,0,bitmap.getWidth(),bitmap.getHeight());

        float roundF = 0.0f;//创建半径变量
        //根据宽高进行比较。使用较短边为半径，创建一个内切圆
        if(bitmap.getWidth() > bitmap.getHeight()){
            roundF= bitmap.getHeight() / 2;
        }else {
            roundF = bitmap.getWidth() / 2;
        }
        //去锯齿效果
        paint.setAntiAlias(true);
        paint.setColor(Color.WHITE);
        //将画板背景设置为透明色
        canvas.drawARGB(0,0,0,0);

        //roundF既是中心点，也是圆的半径
        canvas.drawCircle(roundF,roundF,roundF,paint);
        Rect src = new Rect(0,0,bitmap.getWidth(),bitmap.getHeight());
        //采用Xfermode来进行图片叠加。SRC_IN将取2张图的相交部分。如果想要具体了解Xfermode。
        //可以参考https://blog.csdn.net/u011418943/article/details/79310254网站
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
        //将原始图片绘制到画板上。
        canvas.drawBitmap(bitmap,rect,src,paint);
        return circleBitmap;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //绘制波浪图路经
        getPathData();
        //将该路径绘制到画板中
        canvas.drawPath(path,paint);
        //获得中间线与波浪图的相交点。region对象是在getPathData中创建并设置的
        Rect bounds = region.getBounds();
        //将头像绘制到中间点。需要注意我们起始点是在左上角。所以我们需要减去图片宽度与高度的一半
        canvas.drawBitmap(bitmap,bounds.left-bitmap.getWidth()/2,
                bounds.top-bitmap.getHeight(),paint);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        width = MeasureSpec.getSize(widthMeasureSpec);
        height = MeasureSpec.getSize(heightMeasureSpec);
        //如果没有设置水平线，那么将水平线的Y坐标设置在最底部
        if(originY == 0){
            originY =height-waveHeight;
        }
    }


    private void getPathData() {
        path.reset();
        //我们绘制半个周长，另半个周长只需要进行反转即可
        int halfWaveLength = waveLength/2;
        //将路经设置到水平起点线
        //dx是动画的增量，随着dx每次增加，波浪图都会向前移动。当移动一个周期后dx又会变成0。如此重复执行
        //originY是水平起始点 如果要实现涨潮效果，我们可以给originY增加一个增量dy。这里没做该效果
        //注：-waveLength是让它超出屏幕一个周长
        path.moveTo(-waveLength+dx,originY);
        //绘制波浪图，超出屏幕宽度后，多绘制一个波浪周期
        for(float i = -waveLength;i<width+waveLength; i+= waveLength){
            //这里是采用了相对贝塞尔曲线进行绘制、rQuadTo会以上一个结束点为参照物进行绘制。
            //param1。拐点的x坐标。param2 拐点的y坐标，param3 终点x坐标，param4 终点y坐标
            //绘制上半个波浪图
            path.rQuadTo(halfWaveLength/2,waveHeight,halfWaveLength,0);
            //绘制下半个波浪图
            path.rQuadTo(halfWaveLength/2,-waveHeight,halfWaveLength,0);
        }
        //上面只是有了波浪路经，我们需要绘制一个封闭路经。这样我们设置画笔的填充效果才有用。
        //绘制右边的结束点
        path.lineTo(width,height);
        //绘制左边结束点
        path.lineTo(0,height);
        //自动与起点进行关闭
        //小伙伴们可以根据坐标进行脑补这个区域效果。它就是一个波浪图填充区域。可能有小伙伴认为这是一个
        //不规则的波浪图。但是不规则区域全部在屏幕之外。我们看不见的。所以能看见的部分是一个规则波浪图
        path.close();

        //创建一个矩形区域。
        region = new Region();
        //该区域刚好在正中间，该区域宽度只有一个像素，相当于就是中间线。用来处理与path相交点。
        Region clip = new Region(width/2,0,width/2+1,height);
        //将path设置到该区域中。用来获取x坐标与y坐标。
        region.setPath(path,clip);
    }

    public void startAnim(){
        //创建一个0-1的属性动画
        ValueAnimator valueAnimator = ValueAnimator.ofFloat(0,1);
        //设置动画执行时间
        valueAnimator.setDuration(during);
        //设置动画无限循环
        valueAnimator.setRepeatCount(ValueAnimator.INFINITE);
        //设置动画为线性插值器（动画是匀速执行）。默认是加速插值器。也就是动画越来越快
        valueAnimator.setInterpolator(new LinearInterpolator());
        //设置动画变化时监听器
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                //获取属性动画的增量因子但fx的值是0-1
                float fx = (float)animation.getAnimatedValue();
                //增量因子*波长，那么波浪将水平进行单位距离。最长就是一个波长。最短就是没有移动
                dx = (int)(fx*waveLength);
                //控制涨潮效果单位因子。这里随便写的一个值，感兴趣的小伙伴可以试一试
                dy -= 2;
                //立即刷新界面，就会调用onDraw方法而重新绘制。现在onDraw中的dx变量小伙伴应该明白有什么用了吧
                postInvalidate();
            }
        });
        //开始执行属性动画
        valueAnimator.start();
    }
}
